import pandas as pd
import numpy as np
import random
import sys
sys.path.append('D:/gitee/python-script-new/papertools/')

from papertools import r2

""" 如果需要生成整数数据，同时确保平均数符合要求，可以考虑以下方法：

生成整数数据后调整平均数： 先生成整数数据，然后根据需要的平均数进行调整，以确保平均数符合要求。这种方法可能需要多次调整，以获得满足要求的平均数。这种方法可能会引入一些误差，但可以在很大程度上接近所需的平均数。

使用自定义分布生成整数数据： 如果您需要更精确地控制平均数，可以使用自定义分布生成整数数据。这需要更高级的统计知识和编程技能，但可以更好地控制平均数。

下面是使用第一种方法的示例代码，生成整数数据并调整平均数： """


def generate_integer_dataV1(mean, num_rows=150, min_value=1, max_value=5, columns=None):
    num_cols = len(mean)
    
    # 在这一行代码中，np.random.randint 生成的数据是一个二维数组，其中每一行表示一次抽样（一个数据点），而每一列表示不同的维度或特征。所以，平均数的计算是针对每一列的，即每一列的平均数是平均值的一个分量。如果您希望生成的数据的每一列都具有接近指定平均数的特性，这就是符合您要求的方式。
    
    # max_value 要加 1 的原因是 np.random.randint(a, b) 函数在生成随机整数时，生成的整数范围是从 a 到 b-1。因此，如果您想要包括 max_value 在内，您需要将 max_value 的值加 1 传递给 np.random.randint。

    # 举个例子，如果您想要生成 1 到 5 之间的随机整数，包括 1 和 5，您需要这样调用 
    generated_data = np.random.randint(min_value, max_value + 1, size=(num_rows, num_cols))
    
    # 计算生成数据的平均数
    generated_mean = np.mean(generated_data, axis=0)
    
    # 调整平均数以符合传入的平均数
    adjustment = (mean - generated_mean).astype(int)  # 强制转换为整数类型
    adjustment_matrix = np.tile(adjustment, (num_rows, 1))
    generated_data += adjustment_matrix

    # 创建一个新数据框，列名使用传入的列名或默认生成
    new_data = pd.DataFrame(generated_data, columns=columns)

    return new_data


def get_group_columns(column_names):
    groups = {}
    
    for column in column_names:
        parts = column.split('_')
        key = '_'.join(parts[:-1])  # 使用除最后一个单词外的部分作为键
        
        if key in groups:
            groups[key].append(column)
        else:
            groups[key] = [column]
    
    grouped_columns = list(groups.values())
    return grouped_columns


def generate_integer_dataV3(means,std_devs=None, num_rows=150, min_value=1, max_value=5, columns=None):
    # 一定要使用正态分布的随机数, 指定标准偏差, 否则生成的数据很不合理, 完全无法检验  
    # 2023-1125更新, 最终解决无法检验问题的方法: 
    # 1. 生成数据的时候计算数据的方差, 如果等于0,就重新生成数据,直到方差不为0 ; 
    # 2. 检查变量间的皮尔逊相关系数, 找出相关性高的变量, 将某一列数据重新生成

    if columns is None:
        columns = [f"Column_{i + 1}" for i in range(len(means))]

    grouped_columns = get_group_columns(columns)

    generated_data = []

    total_index = 0  
    for group_index, group in enumerate(grouped_columns):
        for item_index, column in enumerate(group):
            # print(f"Element: {column}, Group Index: {group_index}, item Index: {item_index}")
            # print('total_index: ',total_index)
            # 将列名按组分配给标准差, 生成一列符合正态分布的数据
            # std_deviation = std_devs[group_index]
            # data = np.random.normal(means[total_index], std_deviation, num_rows).astype(int)
            # 限制数据范围在 min_value 到 max_value 之间
            # data = np.clip(data, min_value, max_value)

            while True:
                data = r2.test_random_int(means[total_index], num_rows)
                # 计算数据的方差
                variance = np.var(data)
                if variance != 0:
                        break
            generated_data.append(data)

            total_index +=1

    df = pd.DataFrame(generated_data).T
    df.columns = columns

    return df

file_path = 'dest/20231106-101631_truncatedNew.xlsx'  # 请替换为你的Excel文件路径

# 读取sheet1的数据
data_from_sheet1 = pd.read_excel(file_path, sheet_name='Sheet1')
# iloc[0]是一个pandas库中的函数，用于获取数据框中的第一行数据。在这里，我们使用iloc[0]来获取Excel文件中第一行的数据。如果你想获取其他行的数据，只需将0替换为所需的行号即可
mean_values = data_from_sheet1.iloc[0].values

std_dev_array = [0.4, 0.5, 0.8, 0.6, 0.2]  # 每个维度的标准差

# 调用函数生成数据
generated_data = generate_integer_dataV3(mean_values,std_devs=std_dev_array,columns=data_from_sheet1.columns)

# 创建一个名为 random_data 的新数据框（DataFrame），并将其赋值为空数据框。
# random_data = pd.DataFrame()

# 遍历原表的25列数据
""" for index,col in enumerate(data_from_sheet1.columns):
    # temp_data = pd.DataFrame()
    print(col)
     # 从data_from_sheet中提取标题栏和第二行数据作为平均值 """


# 保存生成的数据到sheet2
with pd.ExcelWriter(file_path, mode='a', engine='openpyxl') as writer:
    generated_data.to_excel(writer, sheet_name='Sheet2', index=False)

print("Data generated and saved to Sheet2.")
